<!DOCTYPE html>
<html>
<head hexo-theme='Volantis' version='1.6.3' docs='https://volantis.js.org/'>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  
  <title>1-4-FPGA时序约束理论篇之时钟周期约束 | voiue</title>
  
  

  

  <meta name="HandheldFriendly" content="True" />
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <!-- meta -->
  

  <!-- link -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/css/all.min.css">
  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css">

  
  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-waves@0.7.6/dist/waves.min.css">

  

  

  
  <link rel="shortcut icon" type='image/x-icon' href="/avatar/favicon.ico">
  

  
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer@1.10/dist/APlayer.min.css">
  

  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-volantis@1.6.3/css/style.css">

  

  <script>
    function setLoadingBarProgress(num) {
      document.getElementById('loading-bar').style.width=num+"%";
    }
  </script>

  
  
</head>

<body>
  
  <div class="cover-wrapper">
    <cover class='cover post half'>
      
        
  <p class="title ">VOIUE</p>
  
    <p class="subtitle ">「路漫漫其修远兮 吾将上下而求索」</p>
  


  <div class="m_search">
    <form name="searchform" class="form u-search-form">
      <i class="icon fas fa-search fa-fw"></i>
      <input type="text" class="input u-search-input" placeholder="" />
    </form>
  </div>

<div class='menu navigation'>
  <ul class='h-list'>
    
      
        <li>
          <a class="nav home "
            href="/"
            
            
            id="home">
            <i class='fas fa-house-damage fa-fw'></i>&nbsp;主页
          </a>
        </li>
      
        <li>
          <a class="nav home "
            href="/blog/archives/"
            
            
            id="blogarchives">
            <i class='fas fa-archive fa-fw'></i>&nbsp;归档
          </a>
        </li>
      
        <li>
          <a class="nav home "
            href="/wiki/"
            
            
            id="wiki">
            <i class='fas fa-landmark fa-fw'></i>&nbsp;Wiki
          </a>
        </li>
      
        <li>
          <a class="nav home "
            href="/friends/"
            
            
            id="friends">
            <i class='fas fa-link fa-fw'></i>&nbsp;友链
          </a>
        </li>
      
        <li>
          <a class="nav home "
            href="/about/"
            
            
            id="about">
            <i class='fas fa-info-circle fa-fw'></i>&nbsp;关于
          </a>
        </li>
      
    
  </ul>
</div>

      
    </cover>
    <header class="l_header nav-blur">
  <div id="loading-bar-wrapper">
    <div id="loading-bar"></div>
  </div>
	<div class='wrapper'>
		<div class="nav-main container container--flex">
      
        <a class="logo flat-box" target="_self" href='/' >
          
            
              
              
                VOIUE
              
            
          
        </a>
      

			<div class='menu navigation'>
				<ul class='h-list'>
          
  					
  						<li>
								<a class="nav flat-box" href="/"
                  
                  
                  id="home">
									<i class='fas fa-clock fa-fw'></i>&nbsp;近期
								</a>
							</li>
      			
  						<li>
								<a class="nav flat-box" href="/blog/categories/"
                  
                  
                  id="blogcategories">
									<i class='fab fa-apple fa-fw'></i>&nbsp;开发
								</a>
							</li>
      			
  						<li>
								<a class="nav flat-box" href="/blog/archives/"
                  
                  
                  id="blogarchives">
									<i class='fas fa-archive fa-fw'></i>&nbsp;归档
								</a>
							</li>
      			
  						<li>
								<a class="nav flat-box" href="/about/"
                  
                  
                  id="about">
									<i class='fas fa-info-circle fa-fw'></i>&nbsp;关于
								</a>
							</li>
      			
      		
				</ul>
			</div>

      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <i class="icon fas fa-search fa-fw"></i>
          <input type="text" class="input u-search-input" placeholder="搜索一下" />
        </form>
      </div>

			<ul class='switcher h-list'>
				
					<li class='s-search'><a class="fas fa-search fa-fw" target="_self" href='javascript:void(0)'></a></li>
				
				<li class='s-menu'><a class="fas fa-bars fa-fw" target="_self" href='javascript:void(0)'></a></li>
			</ul>
		</div>

		<div class='nav-sub container container--flex'>
			<a class="logo flat-box"></a>
			<ul class='switcher h-list'>
				<li class='s-comment'><a class="flat-btn fas fa-comments fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
          <li class='s-toc'><a class="flat-btn fas fa-list fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
			</ul>
		</div>
	</div>
</header>
	<aside class="menu-phone white-box">
    <header>
		<nav class="menu navigation">
      <ul>
        
          
            <li>
							<a class="nav flat-box" href="/"
                
                
                id="home">
								<i class='fas fa-clock fa-fw'></i>&nbsp;近期
							</a>
            </li>
          
            <li>
							<a class="nav flat-box" href="/blog/categories/"
                
                
                id="blogcategories">
								<i class='fab fa-apple fa-fw'></i>&nbsp;开发
							</a>
            </li>
          
            <li>
							<a class="nav flat-box" href="/blog/archives/"
                
                
                id="blogarchives">
								<i class='fas fa-archive fa-fw'></i>&nbsp;归档
							</a>
            </li>
          
            <li>
							<a class="nav flat-box" href="/about/"
                
                
                id="about">
								<i class='fas fa-info-circle fa-fw'></i>&nbsp;关于
							</a>
            </li>
          
       
      </ul>
		</nav>
    </header>
	</aside>
<script>setLoadingBarProgress(40);</script>

  </div>


  <div class="l_body">
    <div class='body-wrapper'>
      

<div class='l_main'>
  

  
    <article id="post" class="post white-box   article-type-post" itemscope itemprop="blogPost">
      


  <section class='meta'>
    
    
    <div class="meta" id="header-meta">
      
        
  
    <h1 class="title">
      <a href="/blog/2020-06-05-1-4-clock-period-constraints/">
        1-4-FPGA时序约束理论篇之时钟周期约束
      </a>
    </h1>
  


      
      <div class='new-meta-box'>
        
          
        
          
            
<div class='new-meta-item author'>
  <a href="https://voiue.gitee.io" rel="nofollow">
    <img src="/avatar/avatar.jpg">
    <p>voiue</p>
  </a>
</div>

          
        
          
            
  
  <div class='new-meta-item category'>
    <a href='/blog/categories/Dev/FPGA/' rel="nofollow">
      <i class="fas fa-folder-open" aria-hidden="true"></i>
      <p>Dev&nbsp;/&nbsp;FPGA</p>
    </a>
  </div>


          
        
          
            <div class="new-meta-item date">
  <a class='notlink'>
    <i class="fas fa-edit" aria-hidden="true"></i>
    <p>发布于：2020年6月5日</p>
  </a>
</div>

          
        
          
            

          
        
      </div>
      
        <hr>
      
    </div>
  </section>


      <section class="article typo">
        <div class="article-entry" itemprop="articleBody">
          
          <h3 id="时钟周期约束"><a href="#时钟周期约束" class="headerlink" title="时钟周期约束"></a>时钟周期约束</h3><p>&emsp;&emsp;时钟周期约束，顾名思义，就是我们对时钟的周期进行约束，这个约束是我们用的最多的约束了，也是最重要的约束。</p>
<p>&emsp;&emsp;下面我们讲一些Vivado中时钟约束指令。</p>
<a id="more"></a>

<p> <strong>1. Create_clock</strong></p>
<p>&emsp;&emsp;在Vivado中使用<code>create_clock</code>来创建时钟周期约束。使用方法为：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">create_clock -name &lt;name&gt; -period &lt;period&gt; -waveform &#123;&lt;rise_time&gt; &lt;fall_time&gt;&#125; [get_ports &lt;input_port&gt;]</span><br></pre></td></tr></table></figure>


<table>
<thead>
<tr>
<th>参数</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>-name</td>
<td>时钟名称</td>
</tr>
<tr>
<td>-period</td>
<td>时钟周期，单位为ns</td>
</tr>
<tr>
<td>-waveform</td>
<td>波形参数，第一个参数为时钟的第一个上升沿时刻，第二个参数为时钟的第一个下降沿时刻</td>
</tr>
<tr>
<td>-add</td>
<td>在同一时刻源上定义多个时钟时使用</td>
</tr>
</tbody></table>
<p>&emsp;&emsp;这里的时钟必须是主时钟<code>primary clock</code>，<strong>主时钟</strong>通常有两种情形:一种是时钟由外部时钟源提供，通过时钟引脚进入FPGA，该时钟引脚绑定的时钟为主时钟:另一种是高速收发器(GT)的时钟RXOUTCLK或TXOUTCLK。对于7系列FPGA，需要对GT的这两个时钟手工约束：对于UltraScale FPGA，只需对GT的输入时钟约束即可，Vivado会自动对这两个时钟约束。</p>
<p>&emsp;&emsp;如何确定主时钟是时钟周期约束的关键，除了根据主时钟的两种情形判断之外，还可以借助Tcl脚本判断。</p>
<p>&emsp;&emsp;在vivado自带的example project里面，打开CPU(HDL)的工程，如下图所示。</p>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial10.png"  alt="" />
</fancybox>
</center>

<p>把工程的xdc文件中，<code>create_clock</code>的几项都注释掉。这里解释下端口（Port）和管脚（Pin）。get_ports获取的是FPGA的IO端口，get_pins获取的是FPGA内部子模块的Pin，具体的我们在第14讲的Tcl命令中会讲到。</p>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial11.png"  alt="" />
</fancybox>
</center>

<p>再<code>Open Synthesized Design</code>或者<code>Open Implementation Design</code>，并通过以下两种方式查看主时钟。</p>
<ul>
<li>方式一</li>
</ul>
<p>运行tcl指令<code>report_clock_networks -name mainclock</code>，显示结果如下：</p>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial12.png"  alt="" />
</fancybox>
</center>

<ul>
<li>方式二<br>运行tcl指令<code>check_timing -override_defaults no_clock</code>，显示结果如下：</li>
</ul>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial13.png"  alt="" />
</fancybox>
</center>

<p><strong><em>Vivado中的tcl命令行相当好用，有很多的功能，大家可以开始习惯用起来了。</em></strong></p>
<p>&emsp;&emsp;对于高速收发器的时钟，我们也以Vivado中的CPU example工程为例，看下Xilinx官方是怎么约束的。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># Define the clocks for the GTX blocks</span><br><span class="line">create_clock -name gt0_txusrclk_i -period 12.8 [get_pins mgtEngine&#x2F;ROCKETIO_WRAPPER_TILE_i&#x2F;gt0_ROCKETIO_WRAPPER_TILE_i&#x2F;gtxe2_i&#x2F;TXOUTCLK]</span><br><span class="line">create_clock -name gt2_txusrclk_i -period 12.8 [get_pins mgtEngine&#x2F;ROCKETIO_WRAPPER_TILE_i&#x2F;gt2_ROCKETIO_WRAPPER_TILE_i&#x2F;gtxe2_i&#x2F;TXOUTCLK]</span><br><span class="line">create_clock -name gt4_txusrclk_i -period 12.8 [get_pins mgtEngine&#x2F;ROCKETIO_WRAPPER_TILE_i&#x2F;gt4_ROCKETIO_WRAPPER_TILE_i&#x2F;gtxe2_i&#x2F;TXOUTCLK]</span><br><span class="line">create_clock -name gt6_txusrclk_i -period 12.8 [get_pins mgtEngine&#x2F;ROCKETIO_WRAPPER_TILE_i&#x2F;gt6_ROCKETIO_WRAPPER_TILE_i&#x2F;gtxe2_i&#x2F;TXOUTCLK]</span><br></pre></td></tr></table></figure>






<p>&emsp;&emsp;当系统中有多个主时钟，且这几个主时钟之间存在确定的相位关系时，需要用到<code>-waveform</code>参数。如果有两个主时钟，如下图所示。</p>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial14.png"  alt="" />
</fancybox>
</center>


<p>则时钟约束为：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">create_clock -name clk0 -period 10.0 -waveform &#123;0 5&#125; [get_ports clk0]</span><br><span class="line">create_clock -name clk1 -period 8.0 -waveform &#123;2 8&#125; [get_ports clk1]</span><br></pre></td></tr></table></figure>

<p>约束中的数字的单位默认是ns，若不写<code>wavefrom</code>参数，则默认是占空比为50%且第一个上升沿出现在0时刻。使用<code>report_clocks</code>指令可以查看约束是否生效。还是上面的CPU的例子，把约束都还原到最初的状态。执行<code>report_clocks</code>后，如下所示，我们只列出其中几项内容。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">Clock Report</span><br><span class="line"></span><br><span class="line">Clock           Period(ns)  Waveform(ns)    Attributes  Sources</span><br><span class="line">sysClk          10.000      &#123;0.000 5.000&#125;   P           &#123;sysClk&#125;</span><br><span class="line">gt0_txusrclk_i  12.800      &#123;0.000 6.400&#125;   P           &#123;mgtEngine&#x2F;ROCKETIO_WRAPPER_TILE_i&#x2F;gt0_ROCKETIO_WRAPPER_TILE_i&#x2F;gtxe2_i&#x2F;TXOUTCLK&#125;</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;</span><br><span class="line">Generated Clocks</span><br><span class="line">&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;</span><br><span class="line"></span><br><span class="line">Generated Clock   : clkfbout</span><br><span class="line">Master Source     : clkgen&#x2F;mmcm_adv_inst&#x2F;CLKIN1</span><br><span class="line">Master Clock      : sysClk</span><br><span class="line">Multiply By       : 1</span><br><span class="line">Generated Sources : &#123;clkgen&#x2F;mmcm_adv_inst&#x2F;CLKFBOUT&#125;</span><br><span class="line"></span><br><span class="line">Generated Clock   : cpuClk_4</span><br><span class="line">Master Source     : clkgen&#x2F;mmcm_adv_inst&#x2F;CLKIN1</span><br><span class="line">Master Clock      : sysClk</span><br><span class="line">Edges             : &#123;1 2 3&#125;</span><br><span class="line">Edge Shifts(ns)   : &#123;0.000 5.000 10.000&#125;</span><br><span class="line">Generated Sources : &#123;clkgen&#x2F;mmcm_adv_inst&#x2F;CLKOUT0&#125;</span><br><span class="line">...</span><br></pre></td></tr></table></figure>


<p>&emsp;&emsp;一般来讲，我们的输入时钟都是差分的，此时我们只对P端进行约束即可。如果同时约束了P端和N端，通过<code>report_clock_interaction</code>命令可以看到提示unsafe。这样既会增加内存开销，也会延长编译时间。</p>
<p> <strong>2. create_generated_clock</strong></p>
<p>其使用方法为：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">create_generated_clock -name &lt;generated_clock_name&gt; \</span><br><span class="line">                       -source &lt;master_clock_source_pin_or_port&gt; \</span><br><span class="line">                       -multiply_by &lt;mult_factor&gt; \</span><br><span class="line">                       -divide_by &lt;div_factor&gt; \</span><br><span class="line">                       -master_clock &lt;master_clk&gt; \</span><br><span class="line">                       &lt;pin_or_port&gt;</span><br></pre></td></tr></table></figure>


<table>
<thead>
<tr>
<th>参数</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>-name</td>
<td>时钟名称</td>
</tr>
<tr>
<td>-source</td>
<td>产生该时钟的源时钟</td>
</tr>
<tr>
<td>-multiply_by</td>
<td>源时钟的多少倍频</td>
</tr>
<tr>
<td>-divide_by</td>
<td>源时钟的多少分频</td>
</tr>
</tbody></table>
<p>&emsp;&emsp;从名字就能看出来，这个是约束我们在FPGA内部产生的衍生时钟， 所以参数在中有个<code>-source</code>，就是指定这个时钟是从哪里来的，这个时钟叫做<code>master clock</code>，是指上级时钟，区别于<code>primary clock</code>。<br>它可以是我们上面讲的primary clock，也可以是其他的衍生时钟。该命令不是设定周期或波形，而是描述时钟电路如何对上级时钟进行转换。这种转换可以是下面的关系：</p>
<ul>
<li>简单的频率分频</li>
<li>简单的频率倍频</li>
<li>频率倍频与分频的组合，获得一个非整数的比例，通常由MMCM或PLL完成</li>
<li>相移或波形反相</li>
<li>占空比改变</li>
<li>上述所有关系的组合</li>
</ul>
<br />

<p>&emsp;&emsp;<strong>衍生时钟</strong>又分两种情况：</p>
<ol>
<li>Vivado自动推导的衍生时钟</li>
<li>用户自定义的衍生时钟</li>
</ol>
<p>&emsp;&emsp;首先来看第一种，如果使用PLL或者MMCM，则Vivado会自动推导出一个约束。大家可以打开Vivado中有个叫<code>wavegen</code>的工程，在这个工程中，输入时钟经过PLL输出了2个时钟，如下图所示。<br>（补充：关于DCM/DLL/PLL/MMCM的区别，可参考文章<a href="https://mp.weixin.qq.com/s?__biz=MzU4ODY5ODU5Ng==&mid=2247484106&idx=1&sn=82983a8086732717298436e067a64d4d&chksm=fdd98441caae0d57c99c5b22cf72bfaee2372824406014680be9df1f8d85b3071182fe43656c&mpshare=1&scene=1&srcid=0928ySJ3ud0vfaGS85Teu5Xw&sharer_sharetime=1571051171309&sharer_shareid=296cfe717a7da125d89d5a7bcdf65c18&key=6234e09828e71f223a5bbb62942587523cffdc550c50d6713403e50f0f1a03c87c5b1a6fae054a425e6f27eabfd6e48eb8fd421c5841d8d8b3b054113d8e8650ff4a65e51fa211ebe10dc0a436635167&ascene=1&uin=MzkzMzM2Nzc1&devicetype=Windows+7&version=62070141&lang=zh_CN&pass_ticket=b15xLCDB%2FBp7ALLPd%2FcqR3Z4qIXNCYrUowj5c4g9AzKzb29vj6R%2F%2BP8z8RJvomTk" target="_blank" rel="noopener">DCM/DLL/PLL/MMCM区别</a></p>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial15.png"  alt="" />
</fancybox>
</center>


<p>&emsp;&emsp;但在xdc文件中，并未对这2个输出时钟进行约束，只对输入的时钟进行了约束，若我们使用<code>report_clocks</code>指令，则会看到：</p>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial16.png"  alt="" />
</fancybox>
</center>

<p><em>注：有三个约束是因为PLL会自动输出一个反馈时钟</em></p>
<p>&emsp;&emsp;自动推导的好处在于当MMCM/PLL/BUFR的配置改变而影响到输出时钟的频率和相位时，用户无需改写约束，Vivado仍然可以自动推导出正确的频率/相位信息。劣势在于，用户并不清楚自动推导出的衍生钟的名字，当设计层次改变时，衍生钟的名字也有可能改变。但由于该衍生时钟的约束并非我们自定义的，因此可能会没有关注到它名字的改变，当我们使用者这些衍生时钟进行别的约束时，就会出现错误。</p>
<p>&emsp;&emsp;解决办法是用户自己手动写出自动推导的衍生时钟的名字，也仅仅写出名字即可，其余的不写。如下所示。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">create_generated_clock -name &lt;generated_clock_name&gt; \</span><br><span class="line">                       -source &lt;master_clock_source_pin_or_port&gt;</span><br></pre></td></tr></table></figure>

<p>这一步很容易会被提示critical warning，其实有个很简单的方法，就是name和source都按照vivado中生成的来。具体我们到后面的例子中会讲到。</p>
<p> <strong>3. set_clock_groups</strong></p>
<p> 使用方法为：<br> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">set_clock_groups -asynchronous -group &lt;clock_name_1&gt; -group &lt;clock_name_2&gt;</span><br><span class="line">set_clock_groups -physically_exclusive  -group &lt;clock_name_1&gt; -group &lt;clock_name_2&gt;</span><br></pre></td></tr></table></figure></p>
<p>&emsp;&emsp;这个约束常用的方法有三种，第一种用法是当两个主时钟是异步关系时，使用<code>asynchronous</code>来指定。这个在我们平时用的还是比较多的，一般稍微大点的工程，都会出现至少两个主时钟，而且这两个时钟之间并没有任何的相位关系，这时就要指定：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">create_clock -period 10 -name clk1 [get_ports clk1]</span><br><span class="line">create_clock -period 8 -name clk2 [get_ports clk2]</span><br><span class="line">set_clock_groups -asynchronous -group clk1 -group clk2</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;第二种用法是当我们需要验证同一个时钟端口在不同时钟频率下能否获得时序收敛时使用。比如有两个异步主时钟clk1和clk2，需要验证在clk2频率为100MHz，clk1频率分别为50MHz、100MHz和200MHz下的时序收敛情况，我们就可以这样写。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">create_clock -name clk1A -period 20.0 [get_ports clk1]</span><br><span class="line">create_clock -name clk1B -period 10.0 [get_ports clk1] -add</span><br><span class="line">create_clock -name clk1C -period 5.0  [get_ports clk1] -add </span><br><span class="line">create_clock -name clk2 -period 10.0 [get_ports clk2]</span><br><span class="line">set_clock_groups -physically_exclusive -group clk1A -group clk1B -group clk1C</span><br><span class="line">set_clock_groups -asynchronous -group &quot;clk1A clk1B clk1C&quot; -group clk2</span><br></pre></td></tr></table></figure>
<p>&emsp;&emsp;第三种用法就是当我们使用BUFGMUX时，会有两个输入时钟，但只会有一个时钟被使用。比如MMCM输入100MHz时钟，两个输出分别为50MHz和200MHz，这两个时钟进入了BUFGMUX，如下图所示。</p>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial17.png"  alt="" /></fancybox>
</center>

<p>在这种情况下，我们需要设置的时序约束如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">set_clock_groups -logically_exclusive \</span><br><span class="line">-group [get_clocks -of [get_pins inst_mmcm&#x2F;inst&#x2F;mmcm_adv_inst&#x2F;CLKOUT0]] \</span><br><span class="line">-group [get_clocks -of [get_pins inst_mmcm&#x2F;inst&#x2F;mmcm_adv_inst&#x2F;CLKOUT1]]</span><br></pre></td></tr></table></figure>


<p> <strong>4. 创建虚拟时钟</strong></p>
<p>&emsp;&emsp;虚拟时钟通常用于设定对输入和输出的延迟约束，这个约束其实是属于IO约束中的延迟约束，之所以放到这里来讲，是因为虚拟时钟的创建，用到了本章节讲的一些理论。虚拟时钟和前面讲的延迟约束的使用场景不太相同。顾名思义，虚拟时钟，就是没有与之绑定的物理管脚。<br>虚拟时钟主要用于以下三个场景：</p>
<ul>
<li>外部IO的参考时钟并不是设计中的时钟</li>
<li>FPGA I/O路径参考时钟来源于内部衍生时钟，但与主时钟的频率关系并不是整数倍</li>
<li>针对I/O指定不同的jitter和latency</li>
</ul>
<p>&emsp;&emsp;简而言之，之所以要创建虚拟时钟，对于输入来说，是因为输入到FPGA数据的捕获时钟是FPGA内部产生的，与主时钟频率不同；或者PCB上有Clock Buffer导致时钟延迟不同。对于输出来说，下游器件只接收到FPGA发送过去的数据，并没有随路时钟，用自己内部的时钟去捕获数据。</p>
<p>&emsp;&emsp;如下图所示，在FPGA的A和B端口分别有两个输入，其中捕获A端口的时钟是主时钟，而捕获B端口的时钟是MMCM输出的衍生时钟，而且该衍生时钟与主时钟的频率不是整数倍关系。</p>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial18.png"  alt="" />
</fancybox>
</center>


<p>&emsp;&emsp;这种情况下时序约束如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">create_clock -name sysclk -period 10 [get_ports clkin]</span><br><span class="line">create_clock -name virclk -period 6.4</span><br><span class="line">set_input_delay 2 -clock sysclk [get_ports A]</span><br><span class="line">set_input_delay 2 -clock virclk [get_ports B]</span><br></pre></td></tr></table></figure>
<p>可以看到，创建虚拟时钟用的也是<code>create_clock</code>约束，但后面并没有加<code>get_ports</code>参数，因此被称为虚拟时钟。</p>
<p>&emsp;&emsp;再举个输出的例子，我们常用的UART和SPI，当FPGA通过串口向下游器件发送数据时，仅仅发过去了uart_tx这个数据，下游器件通过自己内部的时钟去捕获uart_tx上的数据，这就需要通过虚拟时钟来约束；而当FPGA通过SPI向下游器件发送数据时，会发送sclk/sda/csn三个信号，其中sclk就是sda的随路时钟，下游器件通过sclk去捕获sda的数据，而不是用自己内部的时钟，这是就不需要虚拟时钟，直接使用<code>set_output_delay</code>即可。</p>
<p>注意，虚拟时钟必须在约束I/O延迟之前被定义。</p>
<ol start="5">
<li>最大最小延迟约束</li>
</ol>
<p>&emsp;&emsp;顾名思义，就是设置路径的max/min delay，主要应用场景有两个：</p>
<ul>
<li>输入管脚的信号经过组合逻辑后直接输出到管脚</li>
<li>异步电路之间的最大最小延迟</li>
</ul>
<center>
<fancybox>
<img src="https://cdn.jsdelivr.net/gh/voiue/cdn-img/img/fpga/timing_toturial19.png"  alt="" />
</fancybox>
</center>

<p>设置方式为：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">set_max_delay &lt;delay&gt; [-datapath_only] [-from &lt;node_list&gt;][-to &lt;node_list&gt;][-through &lt;node_list&gt;]</span><br><span class="line">set_min_delay &lt;delay&gt; [-from &lt;node_list&gt;] [-to &lt;node_list&gt;][-through &lt;node_list&gt;]</span><br></pre></td></tr></table></figure>

<table>
<thead>
<tr>
<th>参数</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>-from</td>
<td>有效的起始节点包含:时钟,input(input)端口,或时序单元(寄存器,RAM)的时钟引脚.</td>
</tr>
<tr>
<td>-to</td>
<td>有效的终止节点包含:时钟,output(inout)端口或时序单元的数据端口.</td>
</tr>
<tr>
<td>-through</td>
<td>有效的节点包含:引脚,端口,线网.</td>
</tr>
</tbody></table>
<p>&emsp;&emsp;max/min delay的约束平时用的相对少一些，因为在跨异步时钟域时，我们往往会设置<code>asynchronous</code>或者<code>false_path</code>。对于异步时钟，我们一般都会通过设计来保证时序能够收敛，而不是通过时序约束来保证。</p>
<br>

 <div style="position: relative; width: 100%; height: 0; padding-bottom: 75%;"><iframe src="//player.bilibili.com/player.html?aid=73006468&page=4" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;"></iframe></div>
          
            <br>
            
              
                
              
                
              
                
              
                
              
                
              
                
                  

<section class="widget copyright  widget-blur desktop mobile">
  <div class='content'>
    
      <blockquote>
        
          
            <p>博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议</p>

          
        
          
            
          
        
          
            <p>本文永久链接是：<a href=https://voiue.gitee.io/blog/2020-06-05-1-4-clock-period-constraints/>https://voiue.gitee.io/blog/2020-06-05-1-4-clock-period-constraints/</a></p>
          
        
      </blockquote>
    
  </div>
</section>

                
              
                
              
            
          
        </div>
        
          <br>
          


  <section class='meta' id="footer-meta">
    <div class='new-meta-box'>
      
        
          

        
      
        
          <div class="new-meta-item date" itemprop="dateUpdated" datetime="2020-06-05T23:57:14+08:00">
  <a class='notlink'>
    <i class="fas fa-save" aria-hidden="true"></i>
    <p>更新于：2020年6月5日</p>
  </a>
</div>

        
      
        
          
  
  <div class="new-meta-item meta-tags"><a class="tag" href="/blog/tags/timing-analysis/" rel="nofollow"><i class="fas fa-hashtag" aria-hidden="true"></i><p>timing-analysis</p></a></div>


        
      
        
          
  <div class="new-meta-item share -mob-share-list">
  <div class="-mob-share-list share-body">
    
      
        <a class="-mob-share-qq" title="QQ好友" rel="external nofollow noopener noreferrer"
          
          href="http://connect.qq.com/widget/shareqq/index.html?url=https://voiue.gitee.io/blog/2020-06-05-1-4-clock-period-constraints/&title=1-4-FPGA时序约束理论篇之时钟周期约束 - voiue&summary=时钟周期约束&emsp;&emsp;时钟周期约束，顾名思义，就是我们对时钟的周期进行约束，这个约束是我们用的最多的约束了，也是最重要的约束。
&emsp;&emsp;下面我们讲一些Vivado中时钟约束指令。"
          
          >
          
            <img src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-assets/logo/128/qq.png">
          
        </a>
      
    
      
        <a class="-mob-share-qzone" title="QQ空间" rel="external nofollow noopener noreferrer"
          
          href="https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=https://voiue.gitee.io/blog/2020-06-05-1-4-clock-period-constraints/&title=1-4-FPGA时序约束理论篇之时钟周期约束 - voiue&summary=时钟周期约束&emsp;&emsp;时钟周期约束，顾名思义，就是我们对时钟的周期进行约束，这个约束是我们用的最多的约束了，也是最重要的约束。
&emsp;&emsp;下面我们讲一些Vivado中时钟约束指令。"
          
          >
          
            <img src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-assets/logo/128/qzone.png">
          
        </a>
      
    
      
        <a class="-mob-share-weibo" title="微博" rel="external nofollow noopener noreferrer"
          
          href="http://service.weibo.com/share/share.php?url=https://voiue.gitee.io/blog/2020-06-05-1-4-clock-period-constraints/&title=1-4-FPGA时序约束理论篇之时钟周期约束 - voiue&summary=时钟周期约束&emsp;&emsp;时钟周期约束，顾名思义，就是我们对时钟的周期进行约束，这个约束是我们用的最多的约束了，也是最重要的约束。
&emsp;&emsp;下面我们讲一些Vivado中时钟约束指令。"
          
          >
          
            <img src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-assets/logo/128/weibo.png">
          
        </a>
      
    
      
        
        <fancybox>
          <a class='qrcode' rel="external nofollow noopener noreferrer" data-fancybox="gallery-qrcode" href="">
            <img style='height:16px;border-radius:0;margin-left:4px' src="">
          </a>
        </fancybox>
      
    
  </div>
</div>


        
      
    </div>
  </section>


        
        
            <div class="prev-next">
                
                    <section class="prev">
                        <span class="art-item-left">
                            <h6><i class="fas fa-chevron-left" aria-hidden="true"></i>&nbsp;上一页</h6>
                            <h4>
                                <a href="/blog/2020-06-06-1-5-Timing-Exceptions/" rel="prev" title="1-5-FPGA时序约束理论篇之两种时序例外">
                                  
                                      1-5-FPGA时序约束理论篇之两种时序例外
                                  
                                </a>
                            </h4>
                            
                                
                                <h6 class="tags">
                                    <a class="tag" href="/blog/tags/timing-analysis/"><i class="fas fa-tag fa-fw" aria-hidden="true"></i> timing-analysis</a>
                                </h6>
                            
                        </span>
                    </section>
                
                
                    <section class="next">
                        <span class="art-item-right" aria-hidden="true">
                            <h6>下一页&nbsp;<i class="fas fa-chevron-right" aria-hidden="true"></i></h6>
                            <h4>
                                <a href="/blog/2020-06-03-1-3-IO-constraints/" rel="prev" title="1-3-FPGA时序约束理论篇之IO约束">
                                    
                                        1-3-FPGA时序约束理论篇之IO约束
                                    
                                </a>
                            </h4>
                            
                                
                                <h6 class="tags">
                                    <a class="tag" href="/blog/tags/timing-analysis/"><i class="fas fa-tag fa-fw" aria-hidden="true"></i> timing-analysis</a>
                                </h6>
                            
                        </span>
                    </section>
                
            </div>
        
      </section>
    </article>
  

  
    <!-- 显示推荐文章和评论 -->



  <article class="post white-box comments  ">
    <section class="article typo">
      <h4><i class="fas fa-comments fa-fw" aria-hidden="true"></i>&nbsp;评论</h4>
      
      
      
      
        <section id="comments">
          <div id="valine_container" class="valine_thread">
            <i class="fas fa-spinner fa-spin fa-fw"></i>
          </div>
        </section>
      
    </section>
  </article>


  




<!-- 根据页面mathjax变量决定是否加载MathJax数学公式js -->



  <script>
    window.subData = {
      title: '1-4-FPGA时序约束理论篇之时钟周期约束',
      tools: true
    }
  </script>


</div>
<aside class='l_side'>
  
    
      
    
      
        


  <section class="widget toc-wrapper  widget-blur desktop mobile">
    
  <header>
    
      <i class="fas fa-list fa-fw" aria-hidden="true"></i><span class='name'>本文目录</span>
    
  </header>


    <div class='content'>
      <ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#时钟周期约束"><span class="toc-text">时钟周期约束</span></a></li></ol>
    </div>
  </section>


      
    
      
    
      
    
      
    
      
    
      
    
  
</aside>

<footer class="clearfix ">
  <br><br>
  
    <br>
    <div class="aplayer-container">
      

  
    <meting-js
      theme='#1BCDFC'
      autoplay='false'
      volume='0.7'
      loop='all'
      order='list'
      fixed='false'
      list-max-height='340px'
      server='netease'
      type='playlist'
      id='363662803'
      list-folded='true'>
    </meting-js>
  


    </div>
  
  
    <div class="social-wrapper">
      
        
          <a href="/atom.xml"
            class="social fas fa-rss flat-btn"
            target="_blank"
            rel="external nofollow noopener noreferrer">
          </a>
        
      
        
          <a href="mailto:voiue@foxmail.com"
            class="social fas fa-envelope flat-btn"
            target="_blank"
            rel="external nofollow noopener noreferrer">
          </a>
        
      
        
          <a href="https://gitee.com/voiue"
            class="social fab fa-github flat-btn"
            target="_blank"
            rel="external nofollow noopener noreferrer">
          </a>
        
      
        
          <a href="https://music.163.com/#/user/home?id=363662803"
            class="social fas fa-headphones-alt flat-btn"
            target="_blank"
            rel="external nofollow noopener noreferrer">
          </a>
        
      
    </div>
  
  <div>
    本站使用
    <a href="https://volantis.js.org/" target="_blank" class="codename">Volantis</a>
    作为主题
    
      ，
      总访问量为
      <span id="busuanzi_value_site_pv"><i class="fas fa-spinner fa-spin fa-fw" aria-hidden="true"></i></span>
      次
    
    。
  </div>
  
    <div class='copyright'>
    <p><a href="https://voiue.gitee.io">Copyright © 2023 voiue</a></p>

    </div>
  
</footer>
<script>setLoadingBarProgress(80);</script>


      <script>setLoadingBarProgress(60);</script>
    </div>
    <a class="s-top fas fa-arrow-up fa-fw" href='javascript:void(0)'></a>
  </div>
  
<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>


  <script>
    
    var SEARCH_SERVICE = "hexo" || "hexo";
    var ROOT = "/" || "/";
    if (!ROOT.endsWith('/')) ROOT += '/';
  </script>


  <script async src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-volantis@1.6.3/js/instant_page.js" type="module" defer integrity="sha384-OeDn4XE77tdHo8pGtE1apMPmAipjoxUQ++eeJa6EtJCfHlvijigWiJpD7VDPWXV1"></script>


  <script async src="https://cdn.jsdelivr.net/npm/aplayer@1.10/dist/APlayer.min.js"></script>
  <script async src="https://cdn.jsdelivr.net/npm/meting@2.0/dist/Meting.min.js"></script>



  
<script src="https://cdn.jsdelivr.net/npm/node-waves@0.7.6/dist/waves.min.js" async></script>

  <script type="text/javascript">
    $(function() {
      Waves.attach('.flat-btn', ['waves-button']);
      Waves.attach('.float-btn', ['waves-button', 'waves-float']);
      Waves.attach('.float-btn-light', ['waves-button', 'waves-float', 'waves-light']);
      Waves.attach('.flat-box', ['waves-block']);
      Waves.attach('.float-box', ['waves-block', 'waves-float']);
      Waves.attach('.waves-image');
      Waves.init();
    });
  </script>


  <script async src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-busuanzi@2.3/js/busuanzi.pure.mini.js"></script>



  
  
  
    
<script src="//cdn.jsdelivr.net/npm/jquery-backstretch@2.1.18/jquery.backstretch.min.js"></script>

    <script type="text/javascript">
      $(function(){
        if ('') {
          $('').backstretch(
          ["https://cdn.jsdelivr.net/gh/voiue/cdn-wallpaper@1.0/abstract/8782D9-08FE07-E5E73E.jpg"],
          {
            duration: "20000",
            fade: "2500"
          });
        } else {
          $.backstretch(
          ["https://cdn.jsdelivr.net/gh/voiue/cdn-wallpaper@1.0/abstract/8782D9-08FE07-E5E73E.jpg"],
          {
            duration: "20000",
            fade: "2500"
          });
        }
      });
    </script>
  









  
    
<script src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-volantis@1.6.3/js/valine.js"></script>

  
  <script>
  var GUEST_INFO = ['nick','mail','link'];
  var guest_info = 'nick,mail,link'.split(',').filter(function(item){
    return GUEST_INFO.indexOf(item) > -1
  });
  var notify = 'true' == true;
  var verify = 'true' == true;
  var valine = new Valine();
  valine.init({
    el: '#valine_container',
    notify: notify,
    verify: verify,
    guest_info: guest_info,
    
    appId: "iTqB5ruHOstPc8XTQkHYdj8W-gzGzoHsz",
    appKey: "6Ta0gDrH0WJHMHOHkHcWCJXu",
    placeholder: "快来评论吧~",
    pageSize:'10',
    avatar:'mp',
    lang:'zh-cn',
    visitor: 'false',
    highlight:'true'
  })
  </script>



  
<script src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-volantis@1.6.3/js/app.js"></script>



  
<script src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-volantis@1.6.3/js/search.js"></script>



  
<script src="https://cdn.jsdelivr.net/gh/xaoxuu/cdn-volantis@1.6.3/js/comment_typing.js"></script>



<!-- 复制 -->

  <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  let COPY_SUCCESS = "复制成功";
  let COPY_FAILURE = "复制失败";
  /*页面载入完成后，创建复制按钮*/
  !function (e, t, a) {
    /* code */
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '  <i class="fa fa-copy"></i><span>复制</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });

      clipboard.on('success', function(e) {
        //您可以加入成功提示
        console.info('Action:', e.action);
        console.info('Text:', e.text);
        console.info('Trigger:', e.trigger);
        success_prompt(COPY_SUCCESS);
        e.clearSelection();
      });
      clipboard.on('error', function(e) {
        //您可以加入失败提示
        console.error('Action:', e.action);
        console.error('Trigger:', e.trigger);
        fail_prompt(COPY_FAILURE);
      });
    }
    initCopyCode();

  }(window, document);

  /**
   * 弹出式提示框，默认1.5秒自动消失
   * @param message 提示信息
   * @param style 提示样式，有alert-success、alert-danger、alert-warning、alert-info
   * @param time 消失时间
   */
  var prompt = function (message, style, time)
  {
      style = (style === undefined) ? 'alert-success' : style;
      time = (time === undefined) ? 1500 : time*1000;
      $('<div>')
          .appendTo('body')
          .addClass('alert ' + style)
          .html(message)
          .show()
          .delay(time)
          .fadeOut();
  };

  // 成功提示
  var success_prompt = function(message, time)
  {
      prompt(message, 'alert-success', time);
  };

  // 失败提示
  var fail_prompt = function(message, time)
  {
      prompt(message, 'alert-danger', time);
  };

  // 提醒
  var warning_prompt = function(message, time)
  {
      prompt(message, 'alert-warning', time);
  };

  // 信息提示
  var info_prompt = function(message, time)
  {
      prompt(message, 'alert-info', time);
  };

</script>




<!-- fancybox -->

  <script src="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script>
<script>
  let LAZY_LOAD_IMAGE = "";
  $(".article-entry").find("fancybox").find("img").each(function () {
      var element = document.createElement("a");
      $(element).attr("data-fancybox", "gallery");
      $(element).attr("href", $(this).attr("src"));
      /* 图片采用懒加载处理时,
       * 一般图片标签内会有个属性名来存放图片的真实地址，比如 data-original,
       * 那么此处将原本的属性名src替换为对应属性名data-original,
       * 修改如下
       */
       if (LAZY_LOAD_IMAGE) {
         $(element).attr("href", $(this).attr("data-original"));
       }
      $(this).wrap(element);
  });
</script>






  <script>setLoadingBarProgress(100);</script>
  <!--动态线条背景-->
  <!-- <script type="text/javascript" color="255,0,0" opacity='0.7' zIndex="-2" count="200" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script> -->
  <!-- 雪花特效 -->
  <script type="text/javascript" src="/js/snow.js"></script>
</body>
</html>
